// 功能点：
// 1、绘制游戏地图
// 2、绘制蛇、绘制食物
// 3、蛇移动的逻辑（上下左右）、开始游戏、暂停游戏
// 4、记录游戏分数、历史最高分、游戏时间
// 6、蛇与食物碰撞检测、更新蛇的长度、重新随机生成食物
// 7、添加音效


// 面向对象的方式编码：
// 三大特性： 1： 封装性  2：继承性  3：多态性
// 面向对象是一种编程思想 （写法有很多种）
// 在ES5 可以采用构造函数+原型的方式实现这种思想


// 构造函数 (用于构建对象的函数)
// 抽象的对象 （设计一款小米苏8的汽车）
function Game() {
    // 添加属性
    // 获取标签
    this.mapElement = document.querySelector(".map");
    this.scoreElement = document.querySelector(".score");
    this.timeElement = document.querySelector(".time");
    this.playButton = document.querySelector(".btn-play");
    this.pauseButton = document.querySelector(".btn-pause");
    this.toggleButton = document.querySelector(".btn-toggle");
    this.rowEl = document.querySelector(".row");
    this.colEl = document.querySelector(".col");
    this.spaceWidthEl = document.querySelector(".space-width");
    this.spaceHeightEl = document.querySelector(".space-height");
    this.createButton = document.querySelector(".btn-create");
    this.audio = document.querySelector(".audio");
    this.audio.volume = 1;//设置音频音量
    this.audioEl = document.getElementById("audio_bg");
    this.audioEl.volume = 0.5;//设置音频音量

    // 记录所有的li标签 存放在二维数组中
    this.elements = [];
    // 记录蛇的li标签 (普通数组)
    this.snakes = [];
    // 获取地图的尺寸
    this.width = this.mapElement.offsetWidth;
    this.height = this.mapElement.offsetHeight;
    // 定义行
    this.row = 20;// 行的数量
    this.col = 20;// 列数量
    this.spaceWidth = Math.floor(this.width / this.col);//方块宽度
    this.spaceHeight = Math.floor(this.height / this.row);//方块高度
    // 初始化。。填充参数
    this.rowEl.value = this.row;// 设置输入框的行
    this.colEl.value = this.col;// 设置输入框的列
    this.spaceWidthEl.value = this.spaceWidth;// 设置方块宽度
    this.spaceHeightEl.value = this.spaceHeight;// 设置方块高度
    // 蛇头的位置  默认值
    this.R = Math.floor(this.row / 2);// 第?行
    this.C = Math.floor(this.col / 2);// 第?列
    // 食物的位置
    this.foodR = 0;
    this.foodC = 0;
    // 蛇移动的方向  (up上  down下  left左  right右)
    this.direction = "right";
    // 定义定时器变量
    this.dingshiqi = null;
    // 定义变量 记录分数
    this.score = 0;
    // 定义变量 记录时长
    this.times = 0;
    this.startTime = 0;
    // 控制音效
    this.isOpen = false;

}

// 在原型对象上添加方法
Game.prototype.init = function () {
    console.log("初始化...")
    // 创建地图
    this.drawMap();
    // 绘制蛇
    this.drawSnake();
    //创建食物
    this.drawFood();
    // 点击生成地图
    this.createMap();
    // 添加交互行为
    this.addEvent();
}

// 绘制地图
Game.prototype.drawMap = function () {
    // 初始化地图
    this.mapElement.innerHTML = "";
    // 重置大数组
    this.elements = [];
    // 循环创建行
    for (var r = 0; r < this.row; r++) {
        // 创建ul标签
        var ul = document.createElement("ul");
        // 设置ul标签的高度
        ul.style.height = this.spaceHeight + "px";
        // 定义小数组
        var arr = [];
        // 循环创建列
        for (var c = 0; c < this.col; c++) {
            // 创建li标签
            var li = document.createElement("li");
            // 设置每个li标签的宽高
            li.style.width = this.spaceWidth + "px";
            li.style.height = this.spaceHeight + "px";
            // 把li标签添加到ul中
            ul.appendChild(li);
            // 把li标签添加到arr数组
            arr.push(li);
        }
        // 把ul标签添加到地图中
        this.mapElement.appendChild(ul);
        // 把arr数组添加到大数组中
        this.elements.push(arr);
    }
}

// 采集表单信息,点击生成地图
Game.prototype.createMap = function () {
    // 记录当前函数作用域的this (此处this指向构造函数实例)
    var that = this;
    // 监听行的输入
    this.rowEl.oninput = function () {
        // 输入的值是字符串 需要转number类型  （此处this指向rowEl标签）
        if (this.value == "") return;
        that.row = this.value - 0;// 输入的行的数量
        that.spaceHeight = Math.floor(that.height / that.row);//计算方块高度
        that.spaceHeightEl.value = that.spaceHeight;// 设置输入框的值为方块高度
    }
    // 监听列的输入
    this.colEl.oninput = function () {
        // 输入的值是字符串 需要转number类型
        if (this.value == "") return;
        that.col = this.value - 0;// 输入的列数量
        that.spaceWidth = Math.floor(that.width / that.col);//计算方块宽度
        that.spaceWidthEl.value = that.spaceWidth;// //  设置输入框的值为方块宽度
    }
    // 点击按钮 生成地图
    this.createButton.onclick = function () {
        // 全局变量
        that.R = Math.floor(that.row / 2);// 第?行
        that.C = Math.floor(that.col / 2);// 第?列

        // 绘制地图
        that.drawMap();
        // 绘制蛇
        that.drawSnake();
        //创建食物
        that.drawFood();
    }
}

// 绘制蛇
Game.prototype.drawSnake = function () {
    this.snakes = [];
    // 默认值 （选择第1行前3个li标签为蛇身体）
    this.elements[this.R][this.C - 2].className = "snake";
    this.elements[this.R][this.C - 1].className = "snake";
    this.elements[this.R][this.C].className = "snake";
    // 方便后续的业务逻辑开展，蛇移动、碰撞等等
    this.snakes.push(this.elements[this.R][this.C - 2]);
    this.snakes.push(this.elements[this.R][this.C - 1]);
    this.snakes.push(this.elements[this.R][this.C]);
}

// 绘制食物
Game.prototype.drawFood = function () {
    this.foodR = Math.floor(Math.random() * this.row);
    this.foodC = Math.floor(Math.random() * this.col);
    // 创建的食物不能出现在蛇身体中
    if (this.elements[this.foodR][this.foodC].className == "snake") {
        // 重新创建食物
        this.drawFood()
    }
    else {
        // 添加食物外观
        this.elements[this.foodR][this.foodC].className = "food";
    }
}

// 控制音频
// 吃东西
Game.prototype.eatVoice = function () {
    // 判断音效是否打开
    if (this.isOpen) {
        this.audio.muted = false;//关闭静音
        this.audio.volume = 1.0;//设置音频音量
        // 吃到东西的音效
        this.audio.src = "./music/eat.mp3";
        // 调用播放方法
        this.audio.play();
        // console.log("执行了..")
    }
}
// 游戏失败
Game.prototype.failVoice = function () {
    // 判断音效是否打开
    if (this.isOpen) {
        
        this.audio.muted = false;//关闭静音
        this.audio.volume = 1.0;//设置音频音量
        // 吃到东西的音效
        this.audio.src = "./music/fail.mp3";
        // 调用播放方法
        this.audio.play();
    }
}

// 蛇移动的逻辑
Game.prototype.snakeMove = function () {
    // C 水平方向的坐标
    if (this.direction == "right") {
        this.C += 1;
    }
    if (this.direction == "left") {
        this.C -= 1;
    }
    // 垂直方向的坐标
    if (this.direction == "up") {
        this.R -= 1;
    }
    if (this.direction == "down") {
        this.R += 1;
    }

    // 限制范围
    if (this.C >= this.col) {
        this.audioEl.pause();
        console.log("游戏结束x坐标不存在（右）");
        this.showMessage("游戏结束x坐标不存在（右）");
        clearInterval(this.dingshiqi);
        this.failVoice();//失败的音效
        return false;
    }
    if (this.C < 0) {
        this.audioEl.pause();
        console.log("游戏结束x坐标不存在（左）");
        this.showMessage("游戏结束x坐标不存在（左）");
        clearInterval(this.dingshiqi);
        this.failVoice();//失败的音效
        return false;
    }
    if (this.R >= this.row) {
        this.audioEl.pause();
        console.log("游戏结束y坐标不存在（下）");
        this.showMessage("游戏结束y坐标不存在（下）");
        clearInterval(this.dingshiqi);
        this.failVoice();//失败的音效
        return false;
    }
    if (this.R < 0) {
        this.audioEl.pause();
        console.log("游戏结束x坐标不存在（上）");
        this.showMessage("游戏结束x坐标不存在（上）");
        clearInterval(this.dingshiqi);
        this.failVoice();//失败的音效
        return false;
    }

    // 蛇和蛇身体接触 提示游戏结束
    for (var i = 0; i < this.snakes.length; i++) {
        if (this.elements[this.R][this.C] == this.snakes[i]) {
            console.log("蛇头不能和身体接触");
            this.audioEl.pause();
            this.showMessage("蛇头不能和身体接触");
            clearInterval(this.dingshiqi);
            this.failVoice();//失败的音效
            return false;
        }
    }


    // 判断蛇与食物是否发生碰撞
    if (this.R == this.foodR && this.C == this.foodC) {
        // 设置li标签的样式
        this.elements[this.R][this.C].className = "snake";
        this.snakes.push(this.elements[this.R][this.C]);
        //  重新生成食物
        this.drawFood();
        // 蛇吃食物了
        this.addScore();
        // 吃东西的音效
        this.eatVoice();
    }

    else {
        // 移除snakes数组中的第一个li标签的背景
        this.snakes[0].className = "";
        // 删除li标签
        this.snakes.shift();
        // 设置li标签的样式
        this.elements[this.R][this.C].className = "snake";
        // 添加下一个元素
        this.snakes.push(this.elements[this.R][this.C]);
    }

    // 记录游戏时长
    this.recardTime();
}

// 计算分数
Game.prototype.addScore = function () {
    this.score += 5;
    this.scoreElement.innerText = this.score;
}
// 记录游戏的时长
Game.prototype.recardTime = function () {
    var endTime = new Date().getTime();
    times = endTime - this.startTime;
    var seconds = times / 1000;
    var h = Math.floor(seconds / 3600);// 小时
    var m = Math.floor(seconds % 3600 / 60);// 分钟数
    var s = Math.floor(seconds % 60);// 秒数
    // 两位字符
    h = h < 10 ? '0' + h : h;
    m = m < 10 ? '0' + m : m;
    s = s < 10 ? '0' + s : s;
    // 拼接字符串
    var text = `${h}:${m}:${s}`;
    // 渲染时间
    this.timeElement.innerHTML = text;
}

// 用户与界面的交互行为
Game.prototype.addEvent = function () {
    // 记录函数作用域的this
    var that = this;
    // 键盘行为
    document.onkeydown = function (event) {
        // 上 右 下 左
        // 上 左 下 右
        // 蛇正在向右移动，禁止按下向左的按键
        if (that.direction == "right" && event.code == "ArrowLeft") {
            return false;//终止代码
        }
        // 蛇正在向左移动，禁止按下向右的按键
        if (that.direction == "left" && event.code == "ArrowRight") {
            return false;//终止代码
        }
        // 蛇正在向上移动，禁止按下向下的按键
        if (that.direction == "up" && event.code == "ArrowDown") {
            return false;//终止代码
        }
        // 蛇正在向下移动，禁止按下向上的按键
        if (that.direction == "down" && event.code == "ArrowUp") {
            return false;//终止代码
        }

        // 判断用户按下的按键
        // console.log(event.code)
        if (event.code == "ArrowDown") {
            that.direction = "down";
        }
        if (event.code == "ArrowUp") {
            that.direction = "up";
        }
        if (event.code == "ArrowLeft") {
            that.direction = "left";
        }
        if (event.code == "ArrowRight") {
            that.direction = "right";
        }

    }
    // 点击开始按钮
    this.playButton.onclick = function () {
        clearInterval(that.dingshiqi);
        that.dingshiqi = setInterval(function () {
            that.snakeMove();
        }, 200)
        // 记录游戏开始的时间戳
        that.startTime = new Date().getTime();
    }
    // 点击暂停
    this.pauseButton.onclick = function () {
        clearInterval(that.dingshiqi);
    }
    // 点击设置音效
    this.toggleButton.onclick = function () {
        that.audioEl = document.getElementById("audio_bg")
        that.audioEl.muted = false;//关闭静音
        that.audio.muted = false;
        if (that.isOpen) {
            that.toggleButton.className = "btn-toggle";
            that.toggleButton.innerText = "已关闭";
            that.isOpen = false;
            // 暂停
            that.audioEl.pause();
        }
        else {
            that.toggleButton.className = "btn-toggle active";
            that.toggleButton.innerText = "已打开";
            that.isOpen = true;
            // 播放背景音乐
            that.audioEl.play();
        }
    }
}

// 添加自定义弹窗
Game.prototype.showMessage = function (msg) {
    // 创建标签
    var div = document.createElement("div");
    div.className = "message";
    // 设置文本
    div.innerHTML = `
        <div class="message-box">
            <button class="btn-close">关闭</button>
            <p>${msg}</p>
        </div>
        `
    // 获取left标签并添加div
    document.querySelector("#app  .left").appendChild(div);

    // 事件委托
    div.onclick = function(event) {
        // 获取事件源
        var el = event.target;
        if(el.className == "btn-close") {
            // 删除元素 (关闭)
            div.remove();
        }
    }
}


// 创建游戏实例
// 具体对象 （把这款小米苏8的汽车生产出来）
var game = new Game();

// 通过实例对象 调用构造函数原型上的方法
game.init();
// console.dir(game.audio);


